package wsi.exp.exp3;

import java.io.File;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.rygh.core.html.table.HtmlTable;
import org.rygh.core.html.table.TableData;
import org.rygh.core.html.table.TableTuple;
import org.rygh.core.model.common.MapList;
import org.rygh.core.util.UIo;
import org.rygh.core.util.UTime;
import org.rygh.core.util.tex.TexTabular;

import wsi.exp.ExpFolderController;
import wsi.exp.exp3.compare.Exp3Comparator;
import wsi.function.Function;
import wsi.script.AppConfig;
import wsi.script.AppXml;

public class Exp3Tex {

	private final Map<String, String> serviceMap = new HashMap<>();
	private final String type;

	private Map<String, Exp3Comparator> comparatorMap;
	private Set<Function> functionSet;

	{
		serviceMap.put("isbndb", "ISBNdb");
		serviceMap.put("library_thing", "LibraryThing");
		serviceMap.put("last_fm", "Last.fm");
		serviceMap.put("music_brainz", "MusicBrainz");
		serviceMap.put("deanclatworthy", "IMDBApi");
		serviceMap.put("mymovieapi", "MyMovieApi");
	}

	public Exp3Tex(String type) {
		super();
		this.type = type;
	}

	private Function[] arrange(String[] services) {
		MapList<String, Function> map = new MapList<>();

		String service = null;

		for (Function f : functionSet) {
			service = f.getService();
			map.put(service, f);
		}

		map.sort(new Comparator<Function>() {

			@Override
			public int compare(Function o1, Function o2) {
				return o1.getName().compareTo(o2.getName());
			}
		});

		int i;

		List<Function> functions = new LinkedList<>();

		for (i = 0; i < services.length; i++) {
			String s = services[i];

			if (!map.containsKey(s))
				continue;

			functions.addAll(map.get(s));
		}

		return functions.toArray(new Function[functions.size()]);
	}

	private String escapeService(String name) {
		if (serviceMap.containsKey(name))
			return serviceMap.get(name);
		else
			return Character.toUpperCase(name.charAt(0)) + name.substring(1);
	}

	public void save() {
		String kdb = AppConfig.shared().getKnowledgeDatabase();

		if (kdb.equals(AppXml.YAGO)) {
			saveTexAveragePrecisionYago();
			saveTexFScoreYago();
		}
	}

	private void saveTexAveragePrecision(int index, Function[] functions,
			MapList<String, TableTuple> tupleMap) {
		TableData data = new TableData();
		TableTuple tuple = new TableTuple();
		data.add(tuple);

		tuple.add("WS", "Function", "AP");

		Set<Integer> hliners = new HashSet<>();
		String key, sname, service = null;
		Exp3Comparator comparator;
		double d;

		for (int i = 0; i < functions.length; i++) {
			Function f = functions[i];

			if (!f.getService().equals(service)) {
				hliners.add(i + 1);
				service = f.getService();
			}

			sname = escapeService(service);

			tuple = new TableTuple();
			data.add(tuple);
			tupleMap.put(sname, tuple);

			tuple.add(sname, f.getEscapedName());

			key = Exp3Comparator.getName(f, 0);
			comparator = comparatorMap.get(key);
			d = comparator.getAveragePrecision();

			tuple.add(String.format("%.0f", d));
		}

		ExpFolderController folder = ExpFolderController.shared();
		File dir = folder.getFolderForExp0();

		UIo.saveFile(
				new File(dir, String.format("%s3_ap_by_%s_%d.html",
						ExpFolderController.EXP, type, index)), new HtmlTable(
						"Aggregated", data).toSimpleString());

		TexTabular tex = new TexTabular(data);
		tex.setHliners(hliners);

		UIo.saveFile(
				new File(dir, String.format("%s3_ap_by_%s_%d.tex",
						ExpFolderController.EXP, type, index)), tex
						.toTexBodyString());
	}

	private void saveTexAveragePrecision2(int index, String[] services,
			MapList<String, TableTuple> tupleMap) {
		StringBuilder sb = new StringBuilder();
		sb.append(String.format("%% generated on %s\n", UTime.toHumanString()));

		// sb.append("\\begin{tabular}{|l|l|}\n");
		// sb.append("\\hline");
		// sb.append("\\bf Functions & \\bf AP \\\\");
		// sb.append("\\hline");

		for (String s : services) {
			String sname = escapeService(s);

			if (!tupleMap.containsKey(sname))
				continue;

			List<TableTuple> values = tupleMap.get(sname);

			sb.append(String.format("\\rotatebox[origin=c]{90}{%s}", sname));
			sb.append("$\\left\\{%\n");
			sb.append("\\begin{array}{l}\n");

			for (TableTuple t : values)
				sb.append(String.format(" \\text{%s} \\\\\n", t.get(1)));

			sb.append("\\end{array}\\right.$ & \n");
			sb.append("\\begin{tabular}{r}");

			for (TableTuple t : values)
				sb.append(String.format(" %s \\\\", t.get(2)));

			sb.append("\\end{tabular} \\\\ \n");
			sb.append("\\hline\n");
		}

		// sb.append("\\end{tabular}");

		//

		ExpFolderController folder = ExpFolderController.shared();
		File dir = folder.getFolderForExp0();

		UIo.saveFile(
				new File(dir, String.format("%s3_ap2_by_%s_%d.tex",
						ExpFolderController.EXP, type, index)), sb.toString());
	}

	private void saveTexAveragePrecisionYago() {
		String[][] ws = {
		/**/{ "music_brainz", "last_fm", "discogs", "deezer" },
		/**/{ "musixmatch", "echonest", "geonames" },
		/**/{ "mymovieapi", "deanclatworthy", "isbndb", "library_thing" }, };

		Function[][] functions = new Function[ws.length][];

		int i;

		for (i = 0; i < ws.length; i++)
			functions[i] = arrange(ws[i]);

		MapList<String, TableTuple> map = new MapList<>();

		for (i = 0; i < ws.length; i++) {
			map.clear();

			saveTexAveragePrecision(i, functions[i], map);
			saveTexAveragePrecision2(i, ws[i], map);
		}
	}

	private void saveTexFScore(int index, Function[] functions,
			MapList<String, TableTuple> tupleMap) {
		TableData data = new TableData();
		TableTuple tuple = new TableTuple();
		data.add(tuple);

		tuple.add("WS", "Function", "Prec.", "Rec.", "FScore");

		Set<Integer> hliners = new HashSet<>();
		String key, sname, service = null;
		Exp3Comparator comparator;

		for (int i = 0; i < functions.length; i++) {
			Function f = functions[i];

			if (!f.getService().equals(service)) {
				hliners.add(i + 1);
				service = f.getService();
			}

			sname = escapeService(service);

			tuple = new TableTuple();
			data.add(tuple);
			tupleMap.put(sname, tuple);

			tuple.add(sname, f.getEscapedName());

			key = Exp3Comparator.getName(f, 10);
			comparator = comparatorMap.get(key);

			tuple.add(String.format("%.0f", comparator.getPrecision()));
			tuple.add(String.format("%.0f", comparator.getRecall()));
			tuple.add(String.format("%.0f", comparator.getFScore()));

			tuple.add(String.format("%.0f", comparator.getAveragePrecision()));
		}

		ExpFolderController folder = ExpFolderController.shared();
		File dir = folder.getFolderForExp0();

		UIo.saveFile(
				new File(dir, String.format("%s3_fs_by_%s_%d.html",
						ExpFolderController.EXP, type, index)), new HtmlTable(
						"Aggregated", data).toSimpleString());

		TexTabular tex = new TexTabular(data);
		tex.setHliners(hliners);

		UIo.saveFile(
				new File(dir, String.format("%s3_fs_by_%s_%d.tex",
						ExpFolderController.EXP, type, index)), tex
						.toTexBodyString());
	}

	private void saveTexFScore2(int index, String[] services,
			MapList<String, TableTuple> tupleMap) {
		StringBuilder sb = new StringBuilder();
		sb.append(String.format("%% generated on %s\n", UTime.toHumanString()));

		// sb.append("\\begin{tabular}{|l|l|}\n");
		// sb.append("\\hline");
		// sb.append("\\bf Functions & \\bf AP \\\\");
		// sb.append("\\hline");

		for (String s : services) {
			String sname = escapeService(s);

			if (!tupleMap.containsKey(sname))
				continue;

			List<TableTuple> values = tupleMap.get(sname);

			sb.append(String.format("\\rotatebox[origin=c]{90}{%s}", sname));
			sb.append("$\\left\\{%\n");
			sb.append("\\begin{array}{l}\n");

			for (TableTuple t : values)
				sb.append(String.format(" \\text{%s} \\\\\n", t.get(1)));

			sb.append("\\end{array}\\right.$ \n");

			for (int j = 2; j < 6; j++) {
				sb.append("& \\begin{tabular}{rrr}");

				for (TableTuple t : values)
					sb.append(String.format(" %s \\\\", t.get(j)));

				sb.append("\\end{tabular} \n");
			}

			sb.append("\\\\ \n\\hline\n");
		}

		// sb.append("\\end{tabular}");

		//

		ExpFolderController folder = ExpFolderController.shared();
		File dir = folder.getFolderForExp0();

		UIo.saveFile(
				new File(dir, String.format("%s3_fs2_by_%s_%d.tex",
						ExpFolderController.EXP, type, index)), sb.toString());
	}

	private void saveTexFScoreYago() {
		String[][] ws = {
				/**/{ "music_brainz", "last_fm", "discogs", "deezer",
						"echonest", "geonames" },
				/**/{ "musixmatch", "mymovieapi", "deanclatworthy", "isbndb",
						"library_thing" }, };

		Function[][] functions = new Function[ws.length][];

		int i;

		for (i = 0; i < ws.length; i++)
			functions[i] = arrange(ws[i]);

		MapList<String, TableTuple> map = new MapList<>();

		for (i = 0; i < ws.length; i++) {
			map.clear();

			saveTexFScore(i, functions[i], map);
			saveTexFScore2(i, ws[i], map);
		}

	}

	public void setComparatorMap(Map<String, Exp3Comparator> comparatorMap) {
		this.comparatorMap = comparatorMap;
	}

	public void setFunctionSet(Set<Function> functionSet) {
		this.functionSet = functionSet;
	}
}
